package com.polaris.live.ui.live.widget

import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.LayoutTransition
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.widget.FrameLayout
import com.google.common.cache.CacheBuilder
import com.polaris.live.R
import com.polaris.live.common.manager.CoroutineScopeManager
import com.polaris.live.databinding.WidgetLiveEnterItemBinding
import com.polaris.live.im.sfs.bean.live.ext.LiveEnterBean
import com.polaris.live.widget.AnimUtils
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.util.LinkedList
import java.util.concurrent.TimeUnit
import kotlin.math.max

/**
 * LiveEnterView
 *
 * @author Created by lucas on 2023/11/17 16:03
 */
class LiveEnterView(context: Context, attributeSet: AttributeSet?) : FrameLayout(context, attributeSet) {

    private val mQueue = LinkedList<LiveEnterBean>()

    private var mCurrentView: View? = null

    private var mAnimating = false
    private var mLastWaitTime: Long? = null
    private var mDelayJob: Job? = null

    //防止用户进进出出的显示
    private val cache = CacheBuilder.newBuilder()
        .maximumSize(1000)
        .expireAfterWrite(30, TimeUnit.SECONDS)
        .build<Long, Long>()

    init {
        setBackgroundResource(R.drawable.r20_back_000000_30)

        layoutTransition = LayoutTransition().apply {
            setAnimateParentHierarchy(false)
        }
    }

    fun addEnterBean(bean: LiveEnterBean) {
        if (cache.getIfPresent(bean.userId) != null) {
            return
        }

        cache.put(bean.userId, System.currentTimeMillis())

        if (mCurrentView != null || mAnimating) {
            if (mQueue.isEmpty() && mAnimating && mDelayJob != null) {
                mDelayJob?.cancel()
                mDelayJob = null

                val lastWaitTime = mLastWaitTime
                val delay = if (lastWaitTime != null) {
                    SWITCH_DURATION - (System.currentTimeMillis() - lastWaitTime)
                } else {
                    0
                }
                toNextStop(mCurrentView, bean, max(delay, 0))
            } else {
                mQueue.add(bean)
            }
        } else {
            startEnterView(bean)
        }
    }

    private fun startEnterView(bean: LiveEnterBean) {
        mAnimating = true

        visibility = INVISIBLE

        addAndRunAnim(bean) {
            AnimUtils.inLeft(this@LiveEnterView, width, {
                addListener(object : AnimatorListenerAdapter() {
                    override fun onAnimationStart(animation: Animator) {
                        this@LiveEnterView.visibility = VISIBLE
                    }
                })
            }) {
                startNextStep()
            }
        }
    }

    private fun nextEnterView(lastView: View?, bean: LiveEnterBean) {
        if (lastView != null) {
            AnimUtils.outTop(lastView, height) {
                post {
                    removeView(lastView)
                }
            }
        }

        addAndRunAnim(bean) {
            AnimUtils.inBottom(root, height) {
                startNextStep()
            }
        }
    }

    private fun addAndRunAnim(bean: LiveEnterBean, block: WidgetLiveEnterItemBinding.() -> Unit) {
        WidgetLiveEnterItemBinding.inflate(LayoutInflater.from(context), this, true).apply {
            mCurrentView = root

            bingView(this, bean)

            post {
                block()
            }
        }
    }

    private fun bingView(binding: WidgetLiveEnterItemBinding, bean: LiveEnterBean) {
        binding.apply {
            root.layoutParams = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT)

            lvLevel.setData(bean.sex, bean.richs, bean.charms)

            userName.text = bean.nickname
        }
    }

    private fun endView() {
        AnimUtils.outLeft(this, width) {
            endNextStep()

            post {
                removeAllViews()
            }

            mCurrentView = null
            mAnimating = false
        }
    }

    private fun startNextStep() {
        val nextBean = mQueue.poll()
        val delay = if (nextBean == null) {
            EXIT_DURATION
        } else {
            SWITCH_DURATION
        }

        toNextStop(mCurrentView, nextBean, delay)
    }

    private fun toNextStop(lastView: View?, nextBean: LiveEnterBean?, delay: Long) {
        mLastWaitTime = System.currentTimeMillis()

        mDelayJob = CoroutineScopeManager.defaultScope.launch {
            try {
                if (delay > 0) {
                    delay(delay)
                }

                withContext(CoroutineScopeManager.mainDispatcher) {
                    if (nextBean != null) {
                        nextEnterView(lastView, nextBean)
                    } else {
                        endView()
                    }
                }
            } finally {
                if (mDelayJob == coroutineContext[Job]) {
                    mDelayJob = null
                }
            }
        }
    }

    private fun endNextStep() {
        val nextBean = mQueue.poll()
        if (nextBean != null) {
            addEnterBean(nextBean)
        }
    }

    override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()

        mDelayJob?.cancel()
        mDelayJob = null
    }

    companion object {

        const val EXIT_DURATION = 3000L
        const val SWITCH_DURATION = 1000L

    }
}